<template>
  <div>
    <n-card style="margin-top: 5px;" :bordered="false">
      <n-grid x-gap="12">
        <n-grid-item :span="24">
          <n-form-item :show-label="false" label="是否使用ControlNet" path="prompt">
            <n-space justify="space-around">
              <n-checkbox
                  v-model:checked="controlNetConfig.enabled"
                  @update:checked="updateEnable">是否使用ControlNet

              </n-checkbox>
              <n-button type="primary" size="small" v-if="controlNetConfig.enabled"
                        @click="controlNetDetect" :loading="controlNetDetectLoading">图片预处理
              </n-button>
            </n-space>
          </n-form-item>
        </n-grid-item>
        <n-grid-item :span="16">
          <n-card title="ControlNet设置" v-if="controlNetConfig.enabled">
            <n-grid x-gap="10" style="margin-bottom: 10px">
              <n-grid-item :span="16">
                <n-checkbox v-model:checked="controlNetConfig.low_vram">低显存模式</n-checkbox>
                <n-checkbox v-model:checked="controlNetConfig.pixel_perfect">完美像素</n-checkbox>
              </n-grid-item>
            </n-grid>

            <n-grid x-gap="10">
              <n-grid-item :span="8">
                <n-form-item label="控制类型">
                  <n-select
                      v-model:value="controlNetConfig.preProcessor"
                      @update:value="updateControlType"
                      :options="controlNetTypeList">
                  </n-select>
                </n-form-item>
                <n-form-item label="控制权重">
                  <n-input-number style="width: 100%;" :min="0" :max="2" :step="0.01"
                                  v-model:value="controlNetConfig.weight">
                  </n-input-number>
                </n-form-item>
              </n-grid-item>
              <n-grid-item :span="8">
                <n-form-item label="预处理器">
                  <n-select
                      :options="module_list"
                      v-model:value="controlNetConfig.module"
                      @update:value="getControlNetDetailConfig"></n-select>
                </n-form-item>

                <n-form-item label="引导接入时机">
                  <n-input-number style="width: 100%;" :min="0" :max="1" :step="0.01"
                                  v-model:value="controlNetConfig.guidance_start">
                  </n-input-number>
                </n-form-item>
              </n-grid-item>
              <n-grid-item :span="8">
                <n-form-item label="模型">
                  <n-select
                      :options="modelList"
                      v-model:value="controlNetConfig.model"
                  >
                  </n-select>
                </n-form-item>
                <n-form-item label="引导终止时机">
                  <n-input-number style="width: 100%;" :min="0" :max="1" :step="0.01"
                                  v-model:value="controlNetConfig.guidance_end">
                  </n-input-number>
                </n-form-item>
              </n-grid-item>
              <n-grid-item :span="12">
                <n-form-item label="控制模式">
                  <n-radio-group v-model:value="controlNetConfig.control_mode">
                    <n-radio value="Balanced">均衡</n-radio>
                    <n-radio value="My prompt is more important">更偏向提示词</n-radio>
                    <n-radio value="ControlNet is more important">更偏向ControlNet</n-radio>
                  </n-radio-group>
                </n-form-item>
              </n-grid-item>
              <n-grid-item :span="12">
                <n-form-item label="缩放模式">
                  <n-radio-group v-model:value="controlNetConfig.resize_mode">
                    <n-radio value="Just Resize">仅调整大小</n-radio>
                    <n-radio value="Scale to Fit (Inner Fit)">裁剪后缩放</n-radio>
                    <n-radio value="Envelope (Outer Fit)">缩放后填充空白</n-radio>
                  </n-radio-group>
                </n-form-item>
              </n-grid-item>
            </n-grid>

            <n-grid x-gap="10" v-if="controlNetFieldConfig">
              <n-grid-item :span="8" v-if="controlNetFieldConfig.preprocessorResolution.enable">
                <n-form-item :label="controlNetFieldConfig.preprocessorResolution.fieldName">
                  <n-input-number
                      :min=controlNetFieldConfig.preprocessorResolution.min
                      :max=controlNetFieldConfig.preprocessorResolution.max
                      :step=controlNetFieldConfig.preprocessorResolution.step
                      :default-value=controlNetFieldConfig.preprocessorResolution.defaultValue
                      v-model:value="controlNetConfig.processor_res">
                  </n-input-number>
                </n-form-item>
              </n-grid-item>
              <n-grid-item :span="8" v-if="controlNetFieldConfig.threshold_a.enable">
                <n-form-item :label="controlNetFieldConfig.threshold_a.fieldName">
                  <n-input-number
                      :min=controlNetFieldConfig.threshold_a.min
                      :max=controlNetFieldConfig.threshold_a.max
                      :step=controlNetFieldConfig.threshold_a.step
                      :default-value=controlNetFieldConfig.threshold_a.defaultValue
                      v-model:value="controlNetConfig.threshold_a">
                  </n-input-number>
                </n-form-item>
              </n-grid-item>
              <n-grid-item :span="8" v-if="controlNetFieldConfig.threshold_b.enable">
                <n-form-item :label="controlNetFieldConfig.threshold_b.fieldName">
                  <n-input-number
                      :min=controlNetFieldConfig.threshold_b.min
                      :max=controlNetFieldConfig.threshold_b.max
                      :step=controlNetFieldConfig.threshold_b.step
                      :default-value=controlNetFieldConfig.threshold_b.defaultValue
                      v-model:value="controlNetConfig.threshold_b">
                  </n-input-number>
                </n-form-item>
              </n-grid-item>
            </n-grid>
          </n-card>
        </n-grid-item>
        <n-grid-item :span="8" v-if="previewImage">
          <n-card title="预览图">
            <n-image
                :src="previewImage"
                v-if="previewImage"
                :width="500"
                alt="结果预览"
                class="image"
                @load="resizeImage"
            >
            </n-image>
          </n-card>
        </n-grid-item>
      </n-grid>
    </n-card>
  </div>
</template>

<script setup lang="ts">
import {onMounted, ref} from 'vue'
import {sdControllerApi} from "@/api/sd/sdController.api"
// @ts-ignore
import fileFunction from "@/libs/globalFunction/file"


const controlNetDetectLoading = ref(false)

const controlNetTypeObj = ref({}) as any
const controlNetTypeList = ref([]) as any
const module_list = ref([]) as any
const modelList = ref([]) as any
const controlNetFieldConfig = ref(null) as any

const previewImage = ref("") as any

const controlNetConfig = ref({
  image: '',
  module: 'None',
  model: 'None',
  weight: 1.0,
  resize_mode: "Scale to Fit (Inner Fit)",
  low_vram: false,
  processor_res: 512,
  threshold_a: null,
  threshold_b: null,
  guidance_start: 0,
  guidance_end: 1,
  control_mode: "Balanced",
  pixel_perfect: true,
  preProcessor: 'Canny',
  enabled: false
})

const props = defineProps({
  resourceId: {
    type: String,
    required: true
  },
  demoImage: {
    type: String,
    required: true
  },
  updateControlNetEnable: {
    required: false,
    type: Function,
    default: (enable:boolean) => {
    }
  }
})


const loadConfig = async (config: any) => {
  if (config.enabled) {
    updateControlType(config.preProcessor)
    await getControlNetDetailConfig(config.module)
  }
  controlNetConfig.value = config
}

const getConfig = () => {
  controlNetConfig.value.image = ''
  return controlNetConfig.value
}

defineExpose({
  loadConfig, getConfig
})

onMounted(() => {
  getControlNetType()
})




const getControlNetType = () => {
  sdControllerApi.getControlNetType(props.resourceId).then(res => {
    if (res.code === 200) {
      controlNetTypeObj.value = res.data.control_types
      controlNetTypeList.value = []
      const keys = Object.keys(controlNetTypeObj.value)
      keys.forEach((key: any) => {
        controlNetTypeList.value.push({
          label: key,
          value: key
        })
      })
      if (controlNetConfig.value.enabled) {
        module_list.value = []
        modelList.value = []
        const key = controlNetConfig.value.preProcessor
        // 查询当前控制类型下的预处理器和模型
        controlNetTypeObj.value[key]['module_list'].forEach((item: any) => {
          module_list.value.push({
            label: item,
            value: item
          })
        })
        controlNetTypeObj.value[key]['model_list'].forEach((item: any) => {
          modelList.value.push({
            label: item,
            value: item
          })
        })
      }
    }
  })
}

// 控制类型选择后
const updateControlType = (key: string) => {
  module_list.value = []
  modelList.value = []
  // 查询当前控制类型下的预处理器和模型
  controlNetTypeObj.value[key]['module_list'].forEach((item: any) => {
    module_list.value.push({
      label: item,
      value: item
    })
  })
  controlNetTypeObj.value[key]['model_list'].forEach((item: any) => {
    modelList.value.push({
      label: item,
      value: item
    })
  })
}


const resetControlNetConfig = () => {
  controlNetFieldConfig.value = {}
  controlNetFieldConfig.value.preprocessorResolution = {}
  controlNetFieldConfig.value.preprocessorResolution.enable = true
  controlNetFieldConfig.value.preprocessorResolution.fieldName = "Preprocessor Resolution"
  controlNetFieldConfig.value.preprocessorResolution.min = 0
  controlNetFieldConfig.value.preprocessorResolution.max = 2048
  controlNetFieldConfig.value.preprocessorResolution.step = 1
  controlNetFieldConfig.value.preprocessorResolution.defaultValue = 512

  controlNetFieldConfig.value.threshold_a = {}
  controlNetFieldConfig.value.threshold_a.enable = false
  controlNetFieldConfig.value.threshold_b = {}
  controlNetFieldConfig.value.threshold_b.enable = false
}


/**
 * 加载controlnet配置
 * @param key 预处理器
 */
const getControlNetDetailConfig = async (key: string) => {
  resetControlNetConfig()
  const configData = await getControlNetModelInfo(key)
  console.log(configData)
  if (configData != null) {
    controlNetFieldConfig.value = configData
    controlNetConfig.value.processor_res = controlNetFieldConfig.value.preprocessorResolution.defaultValue
    controlNetConfig.value.threshold_a = controlNetFieldConfig.value.threshold_a.defaultValue
    controlNetConfig.value.threshold_b = controlNetFieldConfig.value.threshold_b.defaultValue
  }
}


const getControlNetModelInfo = async (moduleName: string) => {
  const param = {
    resourceId: props.resourceId,
    controlNetModuleName: moduleName
  }
  const res = await sdControllerApi.getControlNetModuleInfo(param)
  if (res.code === 200 && res.data != null) {
    return res.data
  } else {
    return null
  }
}

const controlNetDetect = () => {
  if (props.demoImage == null || props.demoImage == '') {
    window.$message.warning("请在测试效果面板中上传图片!!")
    return
  }
  controlNetDetectLoading.value = true
  const controlNetInputImages = []
  controlNetInputImages.push(props.demoImage)
  const param = {
    resourceId: props.resourceId,
    controlNetModule: controlNetConfig.value.module,
    controlNetInputImages: controlNetInputImages,
    controlNetThresholdLow: 54,
    controlNetProcessorRes: 512,
    controlNetThresholdHigh: 54
  }
  sdControllerApi.controlNetDetect(param).then(res => {
    controlNetDetectLoading.value = false
    if (res.code === 200) {
      if (res.data.info == 'Success') {
        previewImage.value = "data:image/png;base64," + res.data.images[0]
      }
    }
  }).finally(() => {
    controlNetDetectLoading.value = false
  })
}

const maxWidth = ref(400)
const maxHeight = ref(400)
const resizeImage = (e: any) => {
  const image = e.target;
  if (image.width > maxWidth.value || image.height > maxHeight.value) {
    const widthRatio = maxWidth.value / image.width;
    const heightRatio = maxHeight.value / image.height;
    const scale = Math.min(widthRatio, heightRatio);
    image.width = image.width * scale;
    image.height = image.height * scale;
  }
}

const updateEnable = (value: boolean) => {
  controlNetConfig.value.enabled = value
  props.updateControlNetEnable(value)
}

</script>
